#include <iostream>
#include <cstring>

// Type Definitions for Token Types
#define TWEET             0
#define AUTHOR            1
#define WORD_TOKEN        11
#define DATE_TOKEN        12
#define YEAR_TOKEN        13
#define HASHTAG_TOKEN     14
#define TWITTER_ADD_TOKEN 15
#define WEB_ADD_TOKEN     16

using namespace std;

////////////////////////////////////////////////////////////////////////////////////////////////////
// CLASS DEFINITIONS
////////////////////////////////////////////////////////////////////////////////////////////////////

/*
 *	LinkedList
 *	Author: Sridhar Radhakrishnan, Matthew A Crist
 *  Date:   September 28, 2011
 *  Course: CS 2413 Data Structures
 *  
 *  This data structure was originally formulated by Sridhar for use in the CS 2413 Data Structures 
 *  course and was used as specified by documentation of Project 002 documentation.  Some elements 
 *  have been updated by Matthew Crist in order to adhere to program conformity and integrity.
 *
 *  This class will allow for an unspecified number of elements to be linked into a sequential order 
 *  and keep track of each tweet that is loaded by the stdin.
 */
template <class DT>
class LinkedList
{
	/* Output operator for this custom linked list. */
	friend ostream& operator<<(ostream&, LinkedList<int>&);

protected:
	DT* _info;								// This information this LinkedList stores
	LinkedList<DT>* _next;					// The next LinkedList item in the chain

public:
	// Constructors
	LinkedList();							// Default
	LinkedList(LinkedList<DT>&);			// Copy
	LinkedList(DT&);						// Argumented to point to the data type passed
	LinkedList(DT&, LinkedList<DT>*);		// Argumented to point to the data type passed and next element
	~LinkedList();							// Destructor

	void add(DT&);							// Sets the information that this LinkedList points
	DT& info();								// Acquires the info stored in this LinkedList
	bool isEmpty();							// Verifies if this LinkedList does not have any elements

	void operator=(const LinkedList<DT>&);	// Assignment operator for this LinkedList
};	// end class

/* This is the default constructor for this class. */
template <class DT>
LinkedList<DT>::LinkedList()
{
	_info = NULL;
	_next = NULL;
}	// end method

/* This constructor will create a new LinkedList linked with the 
 * templated information passed that is stored in the heap. */
template <class DT>
LinkedList<DT>::LinkedList(DT& info)
{
	_info = new DT(info);
	_next = NULL;
}	// end constructor

/* This constructor creates a new LinkedList linked with the templated
 * information passed that is stored in the heap and duplicates it, and 
 * assigns the next LinkedList with the value passed. */
template <class DT>
LinkedList<DT>::LinkedList(DT& info, LinkedList<DT>* next)
{
	_info = new DT(info);
	_next = next;
}	// end constructor

/* Deconstructor for this class that will release the resources that are 
 * used in memory. */
template <class DT>
LinkedList<DT>::~LinkedList()
{
	if(_info != NULL)
	{
		delete _info;
		_info = NULL;
	}	// end if

	if(_next != NULL)
	{
		delete _next;
		_next = NULL;
	}	// end if
}	// end destructor

/* Checks to see if this LinkedList class is empty or does
 * not actually point to a value. */ 
template <class DT>
bool LinkedList<DT>::isEmpty()
{
	return (_info == NULL);
}	// end method

/* Acquires the information in which this LinkedList points 
 * to. */
template <class DT>
DT& LinkedList<DT>::info()
{
	if(isEmpty())
		return NULL;
	else
		return *_info;
}	// end method

/* Adds a new LinkedList item to the LinkedList chain. */
template <class DT>
void LinkedList<DT>::add(DT& value)
{
	if(_next == NULL)
	{
		_next = new LinkedList<DT>(value);
	}
	else
	{
		_next->add(value);
	}	// end if
}	// end method

/* Copies this value into another value for assignment in 
 * order to avoid a bit by bit copy of the LinkedList. */
template <class DT>
void LinkedList<DT>::operator=(const LinkedList<DT>& l_toCopy)
{
	if(_info != NULL)
	{
		delete _info;
		_info = NULL;
	}	// end if

	if(_next != NULL)
	{
		delete _next;
		_next = NULL;
	}	// end if	
}	// end method

/* The output for a LinkedList. */
ostream& operator << (ostream& l_out, LinkedList<int>& l_toWrite)
{
	cout << *(l_toWrite._info);

	if(l_toWrite._next != NULL)
		cout << ", " << *(l_toWrite._next);

	return l_out;
}	// end function

/*
 *	InvertedListItem
 *  Author: Matthew A Crist
 *  Date:   September 28, 2011
 *  Course: CS 2413 Data Structures
 */
class InvertedListItem
{
	/* Writes this InvertedListItem to the outputstream. */
	friend ostream& operator << (ostream&, InvertedListItem&); 

private:
	char*            item;		// The string this ListItem represents
	int              itemType;	// The type of string this ListItem.
	LinkedList<int>* tweetIDs;	// The tweets this string belongs

public:
	// Constructors
	InvertedListItem();					// Default
	InvertedListItem(char*, int);		// String + string type
	InvertedListItem(char*, int, int);	// String + string type + tweet id
	virtual ~InvertedListItem();		// Destructor
	
	void addTweetID(int);				// Adds a tweet this string belongs
	int  getItemType();					// Acquires the type of string

	/* Logical equivalence for this InvertedListItem. */
	bool operator== (const char*) const;
};	// end class

/* Unargumented default constructor for this class. */
InvertedListItem::InvertedListItem()
{
	item     = NULL;
	tweetIDs = NULL;
}	// end constructor

/* Argumented list that creates a new InvertedListItem with the specified 
 * string and item type. */
InvertedListItem::InvertedListItem(char* l_item, int l_itemType)
{
	int length = strlen(l_item);		// Determine the length of the string to be copied
	item       = new char[length+1];	// Allocate enough memory for the string to be copied
	strcpy(item, l_item);				// Assigns the local item value to class value
	itemType   = l_itemType;			// Assigns the local itemType value to class value
	tweetIDs   = NULL;
}	// end constructor

/* Argument list that creates a new InvertedListItem with the specified
 * string and item type assigned to a tweet. */
InvertedListItem::InvertedListItem(char* l_item, int l_itemType, int l_tweetID)
{
	int length = strlen(l_item);		// Determine the length of the string to be copied
	item = new char[length+1];			// Allocate enough memory for the string to be copied
	strcpy(item, l_item);			    // Assigns the local item value to class value
	itemType = l_itemType;				// Assigns the local itemType value to class value
	tweetIDs = NULL;
	addTweetID(l_tweetID);				// Adds a new tweet ID to the list of tweets that 
										// use this InvertedListItem
}	// end constructor

/* Destructor for this class that will free the resources in the head allocated by 
 * the tweetIDs linked list. */
InvertedListItem::~InvertedListItem()
{
	// Verify that there are tweets that are assigned to this InvertedListItem
	if(tweetIDs != NULL)
	{
		delete tweetIDs;	// Remove the tweetIDs LinkedList from the heap.
	}	// end if
}	// end destructor

/* Adds a tweetID to this InvertedListItem that will be used to track the tweets that 
 * use this InvertedListItem in the tweet string.  This is to optimize the memory 
 * utilization of loading tweets and searching. */
void InvertedListItem::addTweetID(int l_tweetID)
{
	if(tweetIDs == NULL)
	{
		tweetIDs = new LinkedList<int>(l_tweetID);
	}
	else
	{
		tweetIDs->add(l_tweetID);	// Adds this tweetID to the LinkedList responsible
										// for tracking the tweets that use this 
				                        // InvertedListItem
	}	// end if
}	// end method

/* Acquires the type of token this InvertiedListItem is.  Possible values are: 
   TWEET, AUTHOR, WORD_TOKEN, DATE_TOKEN, YEAR_TOKEN, HASHTAG_TOKEN, 
   TWITTER_ADD_TOKEN, and WEB_ADD_TOKEN. */
int InvertedListItem::getItemType()
{
	return itemType;
}	// end method

/* Verify the logical equivalence of this InvertedListItem to the string passed. */
bool InvertedListItem::operator==(const char* str) const
{
	int compared = strcmp(item, str);

	if(compared == 0)
		return true;
	else
		return false;
}	// end method

/* Output of this class type to the output stream. 
 * Output format of this clas is described in the 
 * documentation:
 *	Item: InvertedListItem.item
 *	Item Type: InvertedListItem.itemType
 *  Related Tweets: InvertedListItem.tweetIDs
 */
ostream& operator << (ostream& l_out, InvertedListItem& l_toWrite)
{
	if(l_toWrite.getItemType() != TWEET)
	{
		cout << "Item: " << l_toWrite.item << endl;
		cout << "Item Type: ";

		// Determine the Item Type and output the correct string.
		switch(l_toWrite.getItemType())
		{
		case AUTHOR:
			cout << "AUTHOR";
			break;
		case WORD_TOKEN:
			cout << "WORD_TOKEN";
			break;
		case DATE_TOKEN:
			cout << "DATE_TOKEN";
			break;
		case YEAR_TOKEN:
			cout << "YEAR_TOKEN";
			break;
		case HASHTAG_TOKEN:
			cout << "HASHTAG_TOKEN";
			break;
		case TWITTER_ADD_TOKEN:
			cout << "TWITTER_ADD_TOKEN";
			break;
		case WEB_ADD_TOKEN:
			cout << "WEB_ADD_TOKEN";
			break;
		default:
			cout << "UNKNOWN_TOKEN";
		}	// end switch

		cout << endl;

		if(l_toWrite.tweetIDs != NULL)
			cout << "Related tweets: ";
			cout << *(l_toWrite.tweetIDs) << endl;
	}
	else
	{
		cout << l_toWrite.item;
	}

	return l_out;
}	// end method

/*
 *	InvertedList
 *	Author: Matthew A Crist
 *  Date:   September 28, 2011
 *  Course: CS 2413 Data Structures
 *
 *  This class will store all the InvertedListItems
 */
class InvertedList
{
	/* Output specification for this class type. */
	friend ostream& operator << (ostream&, InvertedList&); 

private:
	InvertedListItem* items[500];	// Stores the InvertedListItems for reference
	int               _size;		// Acquires the actual size for searching

public:
	// Constructors
	InvertedList();					// Default
	InvertedList(InvertedList&);	// Copy
	~InvertedList();				// Destructor

	int addItem(char*, int);		// Adds a new item of the specified type
	void addItem(char*, int, int);	// Adds a new item of the specified type at the given index
	int size();						// Acquires the size of this InvertedList
	InvertedListItem* find(char*);	// Locates an InvertedListItem given the value it references

	InvertedListItem operator[](int);	// Index operator for this class
};	// end class

/* Default, unargumented constructor for this class that indicates a 0 length. */
InvertedList::InvertedList()
{
	this->_size = 0;
}	// end constructor

/* Destructor for this class. */
InvertedList::~InvertedList()
{
	if(items != NULL)
	{
		//delete [] items;
	}	// end if
}	// end destructor

/* Adds a new InvertedListItem to the array. */
int InvertedList::addItem(char* l_item, int l_type)
{
	int index = _size;
	// Allocate a new InvertedListItem to the heap, and reference it to the index
	items[index] = new InvertedListItem(l_item, l_type);
	_size++;	// Size has increased, make sure you reflect this

	return index;
}	// end method

/* Adds a new InvertedListItem to the array with given type and referenced to the tweet. */
void InvertedList::addItem(char* l_item, int l_type, int l_tweetID)
{
	InvertedListItem* listItem = find(l_item);
	
	if(listItem != NULL)
	{
		listItem->addTweetID(l_tweetID);
	}
	else
	{
		// Allocate a new InvertedListItem to the head, and reference it to the index
		items[_size] = new InvertedListItem(l_item, l_type, l_tweetID);
		_size++;	// Size has increased
	}
}	// end method

/* Acquires the actual size of this InvertedList. */
int InvertedList::size()
{
	return _size;
}	// end method

/* Locates an InvertedListItem based on the key passed. */
InvertedListItem* InvertedList::find(char* l_key)
{
	// Since this class is unordered, we will do a linear search.
	for(int i = 0; i < _size; i++)
	{
		if(*items[i] == l_key)
		{
			return items[i];
		}	// end if
	}	// end for

	return NULL;
}	// end method

/* The output operator for this InvertedList class. */
ostream& operator<<(ostream& l_out, InvertedList& l_toWrite)
{
	for(int i = 0; i < l_toWrite.size(); i++)
	{
		if(l_toWrite.items[i]->getItemType() == TWEET)
			cout << "[" << i << "] ";
		cout << *l_toWrite.items[i] << endl;
	}	// end for

	return l_out;
}	// end function

/********************************************************************************
*********************************************************************************
********************************************************************************/
// Function definitions
void trim(char*);
int getLength(char*);
void getLine();
void findAuthor();
void findWords(char&);
void getSearchVals();
bool isHashToken(char*);
bool isTwitterAddress(char*);
bool isDate(char*);
bool isYear(char*);
bool isURI(char*);
bool isNum(char&);


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// MAIN FUNCTION
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
char tweetStr[141], wordStr[141], authorStr[141];
char c;
bool tweet_start = false;
bool tweet_end   = false;

int j = 0, k = 0, l = 0;

InvertedList words, dates, years, hashtags, webadds, twitteradds;
InvertedList authorList;		// Where the authors are stored
InvertedList tweetList;			// Where tweets are stored

int main(int argc, char* argv)
{
	cin.get(c);						// The number of tweets
	int tweetCount = (int)c - 48;	// ASCII conversion to int
	cin.get(c);						// newline character - discard

	// Acquire all the author and the tweets from the file.
	for(int i = 0; i < tweetCount; i++)
	{
		findAuthor();
		getLine();
	}
	
	// Print out the tweets
	cout << tweetList << endl;

	getSearchVals();

	return 0;
}	// end function

////////////////////////////////////////////////////////////////////////////////////////////////////////////
// FUNCTION DEFINITIONS
////////////////////////////////////////////////////////////////////////////////////////////////////////////
/* Acquires the first word that follows a tweet, which should be the author of the tweet. */
void findAuthor()
{
	cin.get(c);
	l = 0;
	for(int i = 0; i < 141; i++) authorStr[i] = '\0';

	while(c!= ' ')
	{
		authorStr[l] = c;
		l++;
		cin.get(c);
	}

	trim(authorStr);
	authorList.addItem(authorStr, AUTHOR, tweetList.size());
}

/* Acquires the rest of the line after an author has been acquired. */
void getLine()
{
	for(int i = 0; i < 141; i++) tweetStr[i] = NULL;
	j = 0;

	while(c != '\n')
	{
		tweetStr[j] = c;
		j++;

		findWords(c);
		cin.get(c);
	}

	tweetStr[j] = '\0';

	tweetList.addItem(tweetStr, TWEET);	// The whole line should be stored as the tweet
}

void findWords(char &c)
{
	if(c == ' ' || c == '\n')
	{
		wordStr[k] = '\0';
		trim(wordStr);

		if(strlen(wordStr) > 0)
		{
			if(isHashToken(wordStr))
				hashtags.addItem(wordStr, HASHTAG_TOKEN, tweetList.size());
			else if(isTwitterAddress(wordStr))
				twitteradds.addItem(wordStr, TWITTER_ADD_TOKEN, tweetList.size());
			else if(isDate(wordStr))
				dates.addItem(wordStr, DATE_TOKEN, tweetList.size());
			else if(isYear(wordStr))
				years.addItem(wordStr, YEAR_TOKEN, tweetList.size());
			else if(isURI(wordStr))
				webadds.addItem(wordStr, WEB_ADD_TOKEN, tweetList.size());
			else
				words.addItem(wordStr, WORD_TOKEN, tweetList.size());
		}

		for(int i = 0; i < 141; i++) wordStr[i] = '\0';
		k = 0;

		// Determine the word type.
	}
	else
	{
		wordStr[k] = c;
		k++;
	}	// end if
}	// end function

void getSearchVals()
{
	char search[75];
	int i = 0;

	while(!cin.eof())
	{
		cin.get(c);

		if(c == 'S')
		{
			// search words
			cin.get(c);
			while(c != '\n' && !cin.eof())
			{
				search[i] = c;
				i++;
				cin.get(c);
			}

			search[i] = '\0';
			trim(search);

			InvertedListItem* val = words.find(search);

			cout << "Search result(s) for " << search << " (word):" << endl;
			if(val != NULL)
				cout << *(val) << endl;
			else
				cout << "No match." << endl;

			for(int m = 0; m < 75; m++) search[m] = '\0';
			i = 0;
		}
		else if(c =='D')
		{
			// Search dates
			cin.get(c);
			while(c != '\n' && !cin.eof())
			{
				search[i] = c;
				i++;
				cin.get(c);
			}

			search[i] = '\0';
			trim(search);

			InvertedListItem* val = dates.find(search);

			cout << "Search result(s) for " << search << " (date):" << endl;
			if(val != NULL)
				cout << *(val) << endl;
			else
				cout << "No match." << endl;

			for(int m = 0; m < 75; m++) search[m] = '\0';
			i = 0;
		}
		else if(c =='Y')
		{
			// search years
			cin.get(c);
			while(c != '\n' && !cin.eof())
			{
				search[i] = c;
				i++;
				cin.get(c);
			}

			search[i] = '\0';
			trim(search);

			InvertedListItem* val = years.find(search);

			cout << "Search result(s) for " << search << " (year):" << endl;
			if(val != NULL)
				cout << *(val) << endl;
			else
				cout << "No match." << endl;

			for(int m = 0; m < 75; m++) search[m] = '\0';
			i = 0;
		}
		else if(c == 'H')
		{
			// search hashtags
			cin.get(c);
			while(c != '\n' && !cin.eof())
			{
				search[i] = c;
				i++;
				cin.get(c);
			}

			search[i] = '\0';
			trim(search);

			InvertedListItem* val = hashtags.find(search);

			cout << "Search result(s) for " << search << " (hash tag):" << endl;
			if(val != NULL)
				cout << *(val) << endl;
			else
				cout << "No match." << endl;

			for(int m = 0; m < 75; m++) search[m] = '\0';
			i = 0;
		}
		else if(c == 'W')
		{
			// search web addresses
			cin.get(c);
			while(c != '\n' && !cin.eof())
			{
				search[i] = c;
				i++;
				cin.get(c);
			}

			search[i] = '\0';
			trim(search);

			InvertedListItem* val = webadds.find(search);

			cout << "Search result(s) for " << search << " (web address):" << endl;
			if(val != NULL)
				cout << *(val) << endl;
			else
				cout << "No match." << endl;

			for(int m = 0; m < 75; m++) search[m] = '\0';
			i = 0;
		}
		else if(c =='A')
		{
			// search author
			cin.get(c);
			while(c != '\n' && !cin.eof())
			{
				search[i] = c;
				i++;
				cin.get(c);
			}

			search[i] = '\0';
			trim(search);

			InvertedListItem* val = authorList.find(search);

			cout << "Search result(s) for " << search << " (author):" << endl;
			if(val != NULL)
				cout << *(val) << endl;
			else
				cout << "No match." << endl;

			for(int m = 0; m < 75; m++) search[m] = '\0';
			i = 0;
		}
		else if(c == 'U')
		{
			// search twitter addresses
			cin.get(c);
			while(c != '\n' && !cin.eof())
			{
				search[i] = c;
				i++;
				cin.get(c);
			}

			search[i] = '\0';
			trim(search);

			cout << *(twitteradds.find(search)) << endl;

			for(int m = 0; m < 75; m++) search[m] = '\0';
			i = 0;
		}
	}
}

/*
 * Search the string to see if it contains the '#' character to denote a channel.
 */
bool isHashToken(char* l_eval)
{
	// Is it a hash?
	if(l_eval[0] == '#')
		return true;	// YUP!
	else
		return false;	// NOPE!
}	// end function

/*
 * Search the string to see if it contains the '@' character to denote a twitter user.
 */
bool isTwitterAddress(char* l_eval)
{
	// Is there a twitter addy?
	if(l_eval[0] == '@')
		return true;	// YUP!
	else
		return false;	// NOPE!
}	// end function

/*
 * See if the word contains the date formats specified.
 */
bool isDate(char* l_eval)
{
	// The short date format
	if(getLength(l_eval) == 5)
	{
		if(isNum(l_eval[0]) && isNum(l_eval[1]) && l_eval[2] == '/' && isNum(l_eval[3]) && isNum(l_eval[4]))
		{
			// Compile char to integer (subtract 48 to compensate for ASCII value)
			int month = (((int)l_eval[0] - 48)*10) + ((int)l_eval[1] - 48);

			if(month < 13 && month > 0)
			{	// Month is 01 - 12
				// Compile the day into an integer (accounting for ascii cast)
				int day = (((int)l_eval[3] - 48)*10) + ((int)l_eval[4] - 48);
				if(day < 32 && day > 0)
				{
					// We have a valid date!!!
					return true;
				}
				else
				{
					// No dice.  Day is out of bounds.
					return false;
				}	// end if
			}
			else
			{
				// No dice.  Month is out of bounds.
				return false;
			}	// end if
		}
		else
		{
			// Is not the specified date format.
			return false;
		}	// end if
	} 
	// The long date format
	else if(getLength(l_eval) == 10)
	{
		// xx/xx/xxxx format
		if(isNum(l_eval[0]) && isNum(l_eval[1]) && l_eval[2] == '/' && isNum(l_eval[3]) && isNum(l_eval[4]) && l_eval[5] == '/' && isNum(l_eval[6]) && isNum(l_eval[7]) && isNum(l_eval[8]) && isNum(l_eval[9]))
		{
			// Compile char to integer (subtract 48 to compensate for ASCII value)
			int month = (((int)l_eval[0] - 48)*10) + ((int)l_eval[1] - 48);

			if(month < 13 && month > 0)
			{	// Month is 01 - 12
				// Compile chars to day integer (accounting for ascii cast).
				int day = (((int)l_eval[3] - 48)*10) + ((int)l_eval[4] - 48);
				if(day < 32 && day > 0)
				{
					// Compile chars to year integer (accounting for ascii cast) xxxx
					int year = (((int)l_eval[6] - 48) * 1000) + (((int)l_eval[7] - 48) * 100) + (((int)l_eval[8] - 48) * 10) + ((int)l_eval[9] - 48);

					// Verify the year is within the bounds
					if(year < 2101 && year > 999)
					{
						return true;	// WE HAVE A VALID DATE SON!!!
					}
					else
					{
						return false;	// False alarm!
					}	// end if
				}
				else
				{
					// No dice.  Day is out of bounds.
					return false;
				}	// end if
			}
			else
			{
				// No dice.  Month is out of bounds.
				return false;
			}	// end if
		}
		else
		{
			return false;
		}	// end if
	}
	else
	{
		return false;
	}	// end if
}	// end function

/*
 * Is the value an actual year?  Verify we have a 4 digit number between 1000 and 2100.
 */
bool isYear(char* l_eval)
{
	try		// For giggles (Out of bounds exception?)
	{
		// Verify that the date is 4 numbers and not something else.
		if(isNum(l_eval[0]) && isNum(l_eval[1]) && isNum(l_eval[2]) && isNum(l_eval[3]))
		{
			int year = (((int)l_eval[0] - 48) * 1000) + (((int)l_eval[1] - 48) * 100) + (((int)l_eval[2] - 48) * 10) + ((int)l_eval[3] - 48);
			
			// Verify we are in bounds!
			if(year > 999 && year < 2101)
				return true;	// This is a valid year in the bounds specified.
			else
				return false;	// WRONG!  Date is either too low or too high!!!
		}	// end if
		else
			return false;	// This isn't even a number!!!
	}	// Catch all exceptions and dump to a false. 
	catch(...)
	{
		return false;
	}	// end try/catch
}	// end function

/*
 * Verifies that the character is actually a numeric type (since I cannot use atoi =()
 */
bool isNum(char& l_eval)
{
	// All possibilities for 1 character to be equivalent.
	char* nums = "0123456789";

	// Cycle through all possible decimal unsigned single digital numbers for compare.
	for(int i = 0; i < 10; i++)
	{
		if(nums[i] == l_eval)
			// Match found, we have a number!!!
			return true;
	}	// end for

	return false;
}	// end function

/*
 * This function is responsible for locating the URI indicators in the string and 
 * verifying the following characters.  Key characters are ://, since protocol can 
 * be defined by http, https, ftp, etc...
 *
 * Algorithm:
 * -----------------------------
 * Search for ':'.
 * if next two characters are '/'
 *		is valid URI
 * else
 *		just a colin!
 */
bool isURI(char* l_eval)
{
	int i = 0;

	// Search for the delimiting character ':" and the two hashes that follow.
	while(l_eval[i] != '\0')
	{
		if(l_eval[i] == ':' && l_eval[i+1] == '/' && l_eval[i+2] == '/')
			return true;
		i++;
	}	// end while

	return false;	// Loop has ended an no qualifiers found
}	// end function

/*
 * Trim off all non-essential characters, such as punctuation and quotations from the string, since 
 * they will not be included if we decide to search these words against a query string.
 */
void trim(char* toTrim)
{
	if((toTrim[getLength(toTrim)-1] == '.')  ||		// Don't need a period at the end of a word 
	   (toTrim[getLength(toTrim)-1] == '?')  ||		// Don't need a question at the end of a word
	   (toTrim[getLength(toTrim)-1] == '!')  ||		// We know the word is important enough we don't need to emote it
	   (toTrim[getLength(toTrim)-1] == ',')  ||     // 144 characters could still produce a runon sentence
	   (toTrim[getLength(toTrim)-1] == ':')  ||		// Colon at the end means emphasis, get rid of that thing!
	   (toTrim[getLength(toTrim)-1] == '\"') ||		// No need to keep things in quotes!
	   (toTrim[getLength(toTrim)-1] == ']')  ||		// Author end tag
	   (toTrim[getLength(toTrim)-1] == ' ')  ||     // Whitespace
	   (toTrim[getLength(toTrim)-1] == '\''))		// Less it is slang, we don't want single quotes either
	{
		toTrim[getLength(toTrim)-1] = '\0';			// Replace the last character with the string termination character.
		trim(toTrim);								// End punctuation found, send back through to see if there is more.
	}	// end if

	if((toTrim[0] == '\"') ||						// Word may have been encapsulated in quotations
	   (toTrim[0] == '\'') ||						// I can't think of a word that begins with a single quote, nor can Webster
	   (toTrim[0] == '-')  ||						// Hyphenation should only occur to create quasi words and would be in the middle
	   (toTrim[0] == '[')  ||						// Author begin tag
	   (toTrim[0] == ' ')  ||                       // Whitespace
	   (toTrim[0] == '_'))							// Same as hyphenation, underscores are not needed at the beginning of words
	{
		for(int i = 0; i < getLength(toTrim); i++)	// Need to readjust the indexing of the character array since we took off the beginning
		{
			toTrim[i] = toTrim[i+1];				// Shift the characters to where the previous one was since we trimmed from the front.
		}	// end for

		trim(toTrim);								// Send it back through
	}	// end if
}	// end function

/*
 * Acquires the length of a string based on the location of the last termination character.
 */
int getLength(char* string)
{
	int length = 0;		// Initial length is 0

	// Search for the first occurance of the termination character
	while(string[length] != '\0')
	{
		length++;	// Increment the length until you find it.
	}	// end while

	return length;
}	// end function